//--------------------------------------------------------------------------------
// Alec G Thilenius
//
// This software is distributed under the MIT License, available at the following
// URL:
// http://www.opensource.org/licenses/mit-license.php
//--------------------------------------------------------------------------------

#pragma once;
#include "Assert.h"
#include "Graph.h"
#include "DebugConsole.h"

using namespace AlecThilenius;

inline void SanityTests()
{
	SUITE_BEGIN("GraphTestSuite")
	{
		TEST_BEGIN("Sanity Graph Check");
		{
			Graph _graph;
			VertexPtr _aPtr = _graph.AddVertex("A");
			IsTrue("Create Vertex A", (_aPtr != NULL), "Graph failed to create or return a Vertex.");

			VertexPtr _bPtr = _graph.AddVertex("B");
			IsTrue("Create Vertex B", (_bPtr != NULL), "Graph failed to create or return a Vertex.");

			EdgePtr _e1Ptr = _graph.AddEdge("A", "B", 0.125f);
			IsTrue("Create Edge A->B", (_e1Ptr != NULL), "Graph failed to create or return a Edge.");
		}TEST_END;

		TEST_BEGIN("Sanity VertexPtr Check");
		{
			Graph _graph;

			VertexPtr _aPtr = _graph.AddVertex("A");
			VertexPtr _bPtr = _graph.AddVertex("B");
			EdgePtr _e1Ptr = _graph.AddEdge("A", "B", 0.125f);

			IsTrue("Check VertexPtr Name", (_aPtr->GetName() == "A"), "Names do not match");
			IsTrue("Check VertexPtr Edge Getter", (_aPtr->GetEdgeTo(_bPtr) == _e1Ptr), "Failed to retrieve the correct Edge. - Known architecture bug.");
			IsTrue("Check VertexPtr Weight", (_aPtr->GetWieghtToVertex(_bPtr) == 0.125f), "Failed to retrieve the correct Weight");

			_aPtr->SetWeightToVertex(_bPtr, 0.25f);

			IsTrue("Check VertexPtr Weight Change", (_aPtr->GetWieghtToVertex(_bPtr) == 0.25), "Failed to retrieve the correct weight.");
			IsTrue("Check EdgePtr Weight Change", (_e1Ptr->GetWeight() == 0.25), "EdgePtr failed to update the new weight.");
			
			IsTrue("Vertex count check", (_graph.VerticieCount() == 2), "Incorrect number of Vertex.");
			IsTrue("Edge count check", (_graph.EdgeCount() == 1), "Incorrect number of Edges.");

			//Check getters
			VertexPtr _aGetterPtr = _graph.GetVertex("A");
			IsTrue("Vertex Getter", (_aGetterPtr == _aPtr), "Got bad VertexPtr back from Graph.");

		}TEST_END;

		TEST_BEGIN("Sanity EdgePtr Check");
		{
			Graph _graph;

			VertexPtr _aPtr = _graph.AddVertex("A");
			VertexPtr _bPtr = _graph.AddVertex("B");
			EdgePtr _e1Ptr = _graph.AddEdge("A", "B", 0.125f);

			IsTrue("Check EdgePtr Tail", (_e1Ptr->GetTail() == _aPtr), "EdgePtr failed to return the correct tail VertexPtr.");
			IsTrue("Check EdgePtr Head", (_e1Ptr->GetHead() == _bPtr), "EdgePtr failed to return the correct head VertexPtr.");
			IsTrue("Check EdgePtr Weight", (_e1Ptr->GetWeight() == 0.125f), "EdgePtr failed to return the correct weight.");
			
			_e1Ptr->SetWeight(0.25f);
			IsTrue("Check EdgePtr Weight change", (_e1Ptr->GetWeight() == 0.25f), "EdgePtr failed to update new weight");

			IsTrue("Vertex count check", (_graph.VerticieCount() == 2), "Incorrect number of Vertex.");
			IsTrue("Edge count check", (_graph.EdgeCount() == 1), "Incorrect number of Edges.");

			//Check getters
			EdgePtr _e1GetterPtr = _graph.GetEdge("A", "B");
			IsTrue("Edge Getter", (_e1GetterPtr == _e1Ptr), "Got bad EdgePtr back from Graph.");

		}TEST_END;

		TEST_BEGIN("Sanity NULL Check");
		{

			Graph _graph;

			VertexPtr _aPtr = _graph.AddVertex("A");
			VertexPtr _bPtr = _graph.AddVertex("B");
			EdgePtr _e1Ptr = _graph.AddEdge("A", "B", 0.125f);

			VertexPtr _dneVert1 = _graph.GetVertex("DOES_NOT_EXIST");
			EdgePtr _dneEdge1 = _graph.GetEdge("DOES_NOT_EXIST", "DOES_NOT_EXIT");

			IsTrue("VertexPtr !Null", (!(_dneVert1 == NULL)), "Got null object in place of VertexPtr.");
			IsTrue("VertexPtr Sentinel", (_dneVert1 == _graph.NullVertex), "Sentinel value in _graph does not match _dneVert1" );
			IsTrue("VertexPtr Deref", (_dneVert1->GetName() == "NULL_REFERENCE_VERTEX"), "De-Referencing sentinel pointer give wrong name");

			IsTrue("EdgePtr !Null", (!(_dneEdge1 == NULL)), "Got null object in place of EdgePtr.");
			IsTrue("EdgePte Sentinel", (_dneEdge1 == _graph.NullEdge), "Sentinel value in _graph does not match _dneEdge1" );
			IsTrue("EdgePtr Deref", (_dneEdge1->GetTail()->GetName() == "NULL_REFERENCE_VERTEX" && 
				_dneEdge1->GetHead()->GetName() == "NULL_REFERENCE_VERTEX"), "De-Referencing sentinel pointer give wrong name");

		}TEST_END;

		TEST_BEGIN("Garbage Collection");
		{
			// This should !!NEVER!! be repeated by the user! DO NOT access the raw pointer. Ever.
			Graph _graph;

			Vertex* _aHandle; // UNSAFE!!

			//Create a scope
			{
				VertexPtr _aPtr = _graph.AddVertex("A");
				_aHandle = _aPtr.get(); // UNSAFE!!

				IsTrue("Initial aHandle Check", (_aPtr != NULL && _aHandle != NULL), "aHandle is messed up.");
				IsTrue("Initial Graph count Check", (_graph.VerticieCount() == 1), "There should be 1 Vertex in the graph.");

				IsTrue("Remove Vertex", _graph.RemoveVertex("A"), "Graph failed to remove Vertex.");

				IsTrue("Post Graph count Check", (_graph.VerticieCount() == 0), "There should be 0 Vertex in the graph.");
				IsTrue("A Smart Pointer Check", (_aPtr.get() != NULL), "_aPtr now points to NULL. The Vertex was GCed too early.");
				IsTrue("A Smart Pointer count Check", (_aPtr.use_count() == 1), "We should hold the only 3 references to A.");

				IsTrue("A Handle Check", (_aHandle != NULL), "_aHandle now points to NULL. The Vertex was GCed too early.");

				//TODO - Check Edges before releasing...

			} //Release our smart pointers...
			IsTrue("Dropping Scope...", true, "");

			//TODO - figure out how to tell if the object still existst...

		}TEST_END;

		TEST_BEGIN("Streaming");
		{
			//Create a scope (Not needed)
			{
				// Create a Graph on the stack, name it graphA.
				Graph graphA;

				// Add Verts to it
				graphA.AddVertex("A");
				graphA.AddVertex("B");
				graphA.AddVertex("C");

				// Add Edges to it
				graphA.AddEdge("A", "B", 0.123f);
				graphA.AddEdge("A", "C", 0.456f);

				graphA.AddEdge("B", "A", 0.789f);
				graphA.AddEdge("B", "C", 0.123f);

				graphA.AddEdge("C", "A", 0.456f);
				graphA.AddEdge("C", "B", 0.789f);

				// Open a output file "TestStreamedGraph.txt"
				ofstream oFile;
				oFile.open ("TestStreamedGraph.txt");

				// Stream the graph "graphA" to the file.
				oFile << graphA;

				// Close the file.
				oFile.close();

				// Let the scope drop. graphA no longer exists...
			}

			// Create a Graph on the stack, name it graphB.
			// Note that this graph is compleatly empty.
			Graph graphB;

			// Open a input file "TestStreamedGraph.txt"
			ifstream iFile;
			iFile.open ("TestStreamedGraph.txt");

			// Stream the file into the graph. This has the effect of
			// de-serializing the file into objects
			iFile >> graphB;

			// Close the file
			iFile.close();

			IsTrue("Streamed copy Verts", (graphB.VerticieCount() == 3), "Vertex counts do not match!");
			IsTrue("Streamed copy Edges", (graphB.EdgeCount() == 6), "Edge counts do not match!");

		}TEST_END;
	}
	SUITE_END
}